<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0059)http://203.162.17.98/weblh/suutam/2002/vovisoft/msnet/5.htm -->
<HTML><HEAD><TITLE>Bài 6</TITLE>
<META http-equiv=Content-Type content="text/html; charset=utf-8">
<META content="Le Hoan" name=Author>
<META content="MSHTML 5.50.4134.100" name=GENERATOR>
<META content=FrontPage.Editor.Document name=ProgId>
<META 
content="computer, software, games, vietnam, viet nam, tin hoc, le hoan, pclehoan, ktlehoan, vietnamese, download, saigon, freeware, lehoanpc, mailing list, may tinh, phan cung, phan mem, kien thuc, hop thu, internet, weblh, unicode, Forum, chat, diendan, dien dan" 
name=keywords>
<META 
content="Pho bien kien thuc, huong dan su dung phan cung, phan mem may tinh, game. Download software free. Link website Vietnam, forum, chat, mailing list..." 
name=description></HEAD>
<BODY>
<CENTER>
<P><A href="http://www.vovisoft.com/"><IMG height=77 alt="Logo of Vovisoft" 
src="" width=102 border=0> </A><FONT face=Tahoma></P>
<H2><FONT face=Tahoma color=#800000>Bài 6</FONT></H2>
<H2><FONT face=Tahoma color=#800000>Những chức năng Đối Tượng mới của VB.NET 
(phần III)</FONT></H2></CENTER></FONT><FONT face=Arial>
<BLOCKQUOTE>
  <BLOCKQUOTE>
    <H3><FONT color=green size=2>Dùng OO trong VB.NET</FONT></H3>
    <H3><FONT color=blue size=2>Ngăn cản Thừa kế</FONT></H3>
    <P><FONT size=2>Bình thường (By default) class nào cũng có thể được dùng làm 
    base class để từ đó ta thừa kế. Nhưng đôi khi ta không muốn cho ai thừa kế 
    từ một Class nào đó, để làm việc ấy ta dùng keyword <B>NotInheritable</B> 
    khi declare class:</FONT></P></FONT><FONT face=Tahoma>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>NotInheritable</FONT> <FONT color=blue>Class</FONT> KhôngCon 

<FONT color=blue>End</FONT> <FONT color=blue>Class</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial>
    <P><FONT size=2>Khi ta đã dùng keyword NotInheritable rồi thì không class 
    nào có thể dùng keyword <B>Inherits</B> để tạo một subclass từ class ấy. 
    </FONT></P>
    <H3><FONT color=blue size=2>Thừa kế và Phạm vi hoạt động</FONT></H3>
    <P><FONT size=2>Khi ta dùng đặc tính thừa kế để tạo một SubClass thì class 
    mới nầy có đủ mọi methods, propertỉes và variables với Access Modifier 
    <B>Public</B> hay <B>Friend</B> của SuperClass. Bất cứ thứ gì declared là 
    <B>Private</B> trong SuperClass thì SubClass không thấy hay dùng 
    được.</FONT></P>
    <CENTER>
    <P><I><FONT size=2>Có một ngoại lệ là <B>New</B> method. Các Constructor 
    methods cần phải được implemented (định nghĩa)<BR>lại trong mỗi SubClass. 
    Một chốc nữa ta sẽ bàn vào chi tiết về điểm nầy.</FONT></I></P></CENTER>
    <P><FONT size=2>Để làm sáng tỏ vấn đề SubClass có thể dùng Class Members nào 
    của SuperClass, ta thử code lại <B>Function Amount</B> trong <B>LineItem</B> 
    class bằng cách khiến nó gọi một Private Function tên <B>CalculateAmount</B> 
    để tính ra Amount thay vì để nó tính trực tiếp như trước 
    đây:</FONT></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>Function</FONT> Amount() <FONT color=blue>As</FONT> <FONT color=blue>Single</FONT> 
   <FONT color=blue>Return</FONT> CalculateAmount 
<FONT color=blue>End</FONT> <FONT color=blue>Function</FONT> 

<FONT color=blue>Private</FONT> <FONT color=blue>Function</FONT> CalculateAmount() <FONT color=blue>As</FONT> <FONT color=blue>Single</FONT> 
   <FONT color=blue>Return</FONT> mintQuantity * msngPrice 
<FONT color=blue>End</FONT> <FONT color=blue>Function</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial size=2>
    <P>Khi ta SubClass LineItem để tạo ra ServiceLine class, bất cứ Object 
    ServiceLine nào cũng thừa kế Function Amount vì Function ấy được declared 
    Public trong BaseClass LineItem. Ngược lại, vì Function CalculateAmount là 
    Private nên cả ServiceLine class lẫn bất cứ client code nào dùng một 
    LineItem Object đều không truy cập nó được.<BR><BR>Như thế, mặc dầu ta gọi 
    Function Amount được, nhưng đến phiên nó gọi Private Function 
    CalculateAmount thì có bị trở ngại không? Không sao cả. Vì Function Amount 
    nằm trong cùng Class với Private Function CalculateAmount nên nó có thể gọi 
    được, dù rằng ta gọi Function Amount từ ServiceLine hay client 
    code.<BR><BR>Thí dụ trong client code ta có những hàng code như 
    sau:<BR></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Protected</FONT> <FONT color=blue>Sub</FONT> BtnShowAmount_Click(<FONT color=blue>ByVal</FONT> sender <FONT color=blue>As</FONT> System.Object,  _
                                   <FONT color=blue>ByVal</FONT> e <FONT color=blue>As</FONT> System.EventArgs) <FONT color=blue>Handles</FONT> BtnShowAmount.Click 
   <FONT color=blue>Dim</FONT> Service <FONT color=blue>As</FONT> ServiceLine 
   Service = <FONT color=blue>New</FONT> ServiceLine() 
   Service.Item = "Delivery" 
   Service.Price = 50 
   Service.DateProvided = Now 
   MessageBox.Show (Service.Amount.ToString, "Amount", MessageBoxButtons.OK, MessageBoxIcon.Information) 
<FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial>
    <P><FONT size=2>Kết quả sẽ được hiển thị trong message box, cho thấy 
    Function CalculateAmount được Function Amount gọi dùm cho client code dù 
    rằng cả client code lẫn ServiceLine code đều không thể gọi trực tiếp 
    được.<BR><BR>Điểm nầy nhắc tôi nhớ lại khi còn bé, có lần bà con trong vườn 
    đem ra chợ cho ba má tôi cả thúng xoài thơm rất ngon. Bạn tôi ở lối xóm thấy 
    vậy biểu tôi lén lấy hai trái xoài để ăn vụn. Vì không phải là người nhà nên 
    bạn tôi không thể lấy đuợc xoài, bởi Access Modifier của thún xoài là 
    Private trong nhà tôi. Nhưng vì tôi là Public, nên bạn tôi có thể nhờ tôi 
    lấy dùm. </FONT></P>
    <H3><FONT color=blue size=2>Protected Methods</FONT></H3>
    <P><FONT size=2>Đôi khi <B>Public</B> hay <B>Private</B> thôi chưa đủ. Nếu 
    ta declare thứ gì Private thì nó hoàn toàn giới hạn trong class, ngược lại 
    nếu ta declare nó Public (hay Friend) thì nó có thể được dùng trong 
    subclasses hay client code. <BR><BR>Tuy nhiên, có lúc ta muốn một class 
    member chỉ có thể được dùng trong subclasses thôi, chớ không cho client code 
    dùng. Trong trường hợp ấy ta dùng keyword <B>Protected</B>. Thí 
    dụ:</FONT></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>Class</FONT> FatherClass 
   <FONT color=blue>Protected</FONT> DiSản <FONT color=blue>As</FONT> <FONT color=blue>Single</FONT> 
<FONT color=blue>End</FONT> <FONT color=blue>Class</FONT> 

<FONT color=blue>Public</FONT> <FONT color=blue>Class</FONT> SonClass 
   <FONT color=blue>Inherits</FONT> FatherClass 
   <FONT color=blue>Public</FONT> <FONT color=blue>Function</FONT> ChiaCủa() <FONT color=blue>As</FONT> <FONT color=blue>Single</FONT> 
      <FONT color=blue>Return</FONT> Disản 
   <FONT color=blue>End</FONT> <FONT color=blue>Function</FONT> 
<FONT color=blue>End</FONT> <FONT color=blue>Class</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial>
    <P><FONT size=2>Ở đây ta có BaseClass <B>FatherClass</B> với <B>Protected 
    Field Disản</B>. Không có client code nào có thể thấy Field DiSản được. Thế 
    nhưng bất cứ SubClass nào của FatherClass cũng đều thừa kế và dùng được 
    DiSản.<BR><BR>Trong thí dụ trên, một lần nữa SubClass có một Public method 
    (ChiaCủa) có thể return một protected value - nhưng chính value ấy, DiSản, 
    không trực tiếp cho phép client code dùng. </FONT></P>
    <H3><FONT color=blue size=2>Overriding Methods</FONT></H3>
    <P><FONT size=2>Chúng ta biết rằng đặc tính quan trọng của Inheritance là 
    một SubClass chẳng những thừa kế behaviours của ParentClass mà còn có thể 
    <B>override</B> (lấn quyền) các behaviours ấy nữa. Chúng ta đã thấy một 
    SubClass có thể <B>extend</B> (thêm ra) ParentClass bằng cách cho thêm các 
    methods Public, Protected và Friend. Hơn nữa, khi dùng overriding, một 
    SubClass có thể <B>alter</B> (sửa đổi) behaviours của các methods trong 
    ParentClass.<BR><BR>Bình thường (By default), ta không thể override methods 
    trong ParentClass trừ khi các methods ấy được declared với keyword 
    <B>Overridable</B> trong ParentClass. Thí dụ:</FONT></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>Class</FONT> ClassCha 
   <FONT color=blue>Public</FONT> <FONT color=blue>Overridable</FONT> <FONT color=blue>Sub</FONT> ChàoHỏi() 
      MessageBox.Show("Chào các cháu", "Class Cha") 
   <FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> 
<FONT color=blue>End</FONT> <FONT color=blue>Class</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial size=2>
    <P>Tiếp theo, khi tạo một SubClass, nếu muốn ta có thể override behaviour 
    của <B>Sub ChàoHỏi</B> bằng cách dùng keyword <B>Overrides</B> như 
    sau:<BR></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>Class</FONT> ClassCon 
   <FONT color=blue>Inherits</FONT> ClassCha 
   <FONT color=blue>Public</FONT> <FONT color=blue>Overrides</FONT> <FONT color=blue>Sub</FONT> ChàoHỏi() 
      MessageBox.Show("Thưa các Bác", "Class Con") 
   <FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> 
<FONT color=blue>End</FONT> <FONT color=blue>Class</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial size=2>
    <P>Bây giờ ta có thể viết client code như sau:<BR></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Private</FONT> <FONT color=blue>Sub</FONT> BtnSubClassObject_Click(<FONT color=blue>ByVal</FONT> sender <FONT color=blue>As</FONT> System.Object,   _
                          <FONT color=blue>ByVal</FONT> e <FONT color=blue>As</FONT> System.EventArgs) <FONT color=blue>Handles</FONT> BtnSubClassObject.Click 
   <FONT color=blue>Dim</FONT> obj <FONT color=blue>As</FONT> <FONT color=blue>New</FONT> ClassCon() 
   obj.ChàoHỏi() 
<FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial>
    <P><FONT size=2>Khi ta click button BtnSubClassObject program sẽ hiển thị 
    message dialog dưới đây: </FONT></P>
    <BLOCKQUOTE>
      <P><FONT size=2><IMG height=201 src="" width=341></FONT></P></BLOCKQUOTE>
    <H3><FONT color=#800000 size=2>Virtual Methods</FONT></H3>
    <P><FONT size=2>Tuy nhiên, hãy xem trường hợp ta code như 
    sau:</FONT></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Private</FONT> <FONT color=blue>Sub</FONT> BtnParentClassObject_Click(<FONT color=blue>ByVal</FONT> sender <FONT color=blue>As</FONT> System.Object,  _
                          <FONT color=blue>ByVal</FONT> e <FONT color=blue>As</FONT> System.EventArgs) <FONT color=blue>Handles</FONT> BtnParentClassObject.Click 
   <FONT color=blue>Dim</FONT> obj <FONT color=blue>As</FONT> ClassCha 
   obj = <FONT color=blue>New</FONT> ClassCon() 
   obj.ChàoHỏi() 
<FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial>
    <P><FONT size=2>Trước hết, ở đây có vẻ kỳ kỳ, tại sao declare một variable 
    loại ClassCha mà lại instantiate một object ClassCon. Chuyện đó hoàn toàn 
    bình thường, vì ClassCon <B>là một</B> ClassCha. Tức là một variable loại 
    ClassCha hay ClassCon đều có thể chứa, thật ra là <B>hold references to</B> 
    (point to, chỉ tới), một instance của ClassCon.<BR><BR>Điểm nầy áp dụng tổng 
    quát khi ta dùng Inheritance. Một variable loại SuperClass có thể hold 
    reference to bất cứ SubClass Object nào thừa kế từ SuperClass ấy. Đó là một 
    cách để ta implement tính đa dạng (polymorphism).<BR><BR>Đều có thể làm ta 
    ngạc nhiên là khi ta click button BtnParentClassObject ta cũng thấy hiển thị 
    message "<B> Thưa các Bác</B>". </FONT></P>
    <BLOCKQUOTE>
      <P><FONT size=2><IMG height=200 src="" width=343></FONT></P></BLOCKQUOTE>
    <P><FONT size=2>Sao lạ vậy? Variable <B>obj</B> được declared là ClassCha 
    tại sao message không phải là "<B>Chào các cháu</B>"? Lý do là <B>Sub 
    ChàoHỏi</B> của <B>ClassCon</B> được gọi thay vì Sub ChàoHỏi của ClassCha. 
    Ta nói Sub ChàoHỏi là <B>Virtual</B> method. Tất cả methods trong VB.NET đều 
    là virtual.<BR><BR>Ý niệm virtual để nói rằng cái implementation của <B>con 
    cháu trẻ nhất trong dòng họ</B> được dùng - không cần biết là variable có 
    <B>data type</B> là class của thế hệ nào trong dòng họ. Tức là, nếu variable 
    dùng trong client code hold references to ClassÔngNội, ClassCha, ClassCon 
    hay ClassCháu thì method trong ClassCháu được gọi. Nếu trong ClassCháu không 
    có implementation của method thì ta gọi method trong ClassCon, nếu không có 
    thì gọi method trong ClassCha .v.v.. theo thứ tự từ bề dưới lên bề trên. 
    <BR><BR>Bạn có thể <A 
    href="http://www.vovisoft.com/dotNET/Bai06/ChaConClasses.zip">Download 
    source code</A> của program nầy tại đây. </FONT></P>
    <H3><FONT color=#800000 size=2>Keyword Me</FONT></H3>
    <P><FONT size=2>Keyword <B>Me</B> được dùng khi ta muốn nói rõ (explicitly) 
    rằng ta muốn dùng method của chính cái Class đang chứa code ấy, chớ không 
    phải một implementation nào khác của method ấy.<BR><BR>Cũng có trường hợp ta 
    phải dùng keyword Me để nói ta muốn dùng <B>class-level</B> variable chớ 
    không phải <B>procedure-level</B> variable có cùng tên. Một procedure-level 
    variable, tức là local variable của một method, có cùng tên với một 
    class-level variable được gọi là <B>shadowed</B> variable. Thí 
    dụ:</FONT></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>Class</FONT> TheClass 
   <FONT color=blue>Private</FONT> strName <FONT color=blue>As</FONT> <FONT color=blue>String</FONT> 
   <FONT color=blue>Public</FONT> <FONT color=blue>Sub</FONT> DoSomething() 
      <FONT color=blue>Dim</FONT> strName <FONT color=blue>As</FONT> <FONT color=blue>String</FONT> 
      strName = "Quang" 
   <FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> 
<FONT color=blue>End</FONT> <FONT color=blue>Class</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial size=2>
    <P>Ở đây, variable <B>strName</B> được declared ở class-level và bên trong 
    <B>Sub DoSomething</B>. Bên trong method ấy local variables (kể cả shadowed 
    variables) sẽ được dùng vì chúng che đậy class-level variables trừ khi ta 
    nói rõ rằng phải dùng variable của class-level bằng cách dùng keyword 
    Me:<BR></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>Class</FONT> TheClass 
   <FONT color=blue>Private</FONT> strName <FONT color=blue>As</FONT> <FONT color=blue>String</FONT> 
   <FONT color=blue>Public</FONT> <FONT color=blue>Sub</FONT> DoSomething() 
      <FONT color=blue>Dim</FONT> strName <FONT color=blue>As</FONT> <FONT color=blue>String</FONT> 
      strName = "Quang" <FONT color=green>' thay đổi value của local (shadowed) variable</FONT>
      <FONT color=blue>Me</FONT>.strName = "Kim" <FONT color=green>' thay đổi value của class-level variable</FONT>
   <FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> 
<FONT color=blue>End</FONT> <FONT color=blue>Class</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial>
    <H3><FONT color=#800000 size=2>Keyword MyBase</FONT></H3>
    <P><FONT size=2>Keyword Me rất tiện dụng khi ta muốn dùng Class members của 
    chính Class chứa code. Tương tự như vậy, đôi khi ta muốn dùng Class method 
    của BaseClass (cũng gọi là SuperClass), chớ không phải một implementation 
    của method ấy trong SubClass. Nhớ là một virtual method luôn luôn gọi 
    implementation của Class trẻ nhất.<BR><BR>Từ trong một SubClass, nếu muốn 
    gọi một method của BaseClass ta dùng keyword <B>MyBase</B> như 
    sau:</FONT></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>Class</FONT> ClassCon 
   <FONT color=blue>Inherits</FONT> ClassCha 
   <FONT color=blue>Public</FONT> <FONT color=blue>Overrides</FONT> <FONT color=blue>Sub</FONT> ChàoHỏi() 
      MessageBox.Show("Thưa các Bác", "Class Con") 
      <FONT color=blue>MyBase</FONT>.ChàoHỏi() 
   <FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> 
<FONT color=blue>End</FONT> <FONT color=blue>Class</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial>
    <P><FONT size=2>Bây giờ nếu ta chạy Sub ChàoHỏi của ClassCon ta sẽ có hai 
    messages, một cái từ ClassCon theo sau bởi một cái từ 
    ClassCha.<BR><BR>MyBase chỉ nói đến BaseClass trực tiếp, tức là Class cha 
    thôi chớ không nói đến Class ông nội. Không có cách nào để nói đến hơn một 
    thế hệ.<BR><BR>Dầu vậy, keyword Mybase có thể được dùng cho bất cứ thứ gì đã 
    được declared Public, Friend hay Protected trong ParentClass. Điều nầy kể 
    luôn cả những thứ mà ParentClass thừa kế từ các thế hệ trước trong gia đình, 
    tức là ClassÔngNội, ClassÔngCố .v.v.. </FONT></P>
    <H3><FONT color=#800000 size=2>Keyword MyClass </FONT></H3>
    <P><FONT size=2>Vì lý do virtual method, ta sẽ gặp những trường hợp rắc rối 
    như khi code của ParentClass lại chạy code của SubClasses. <BR><BR>Khi viết 
    code của một class, từ method nầy ta thường gọi những methods khác nằm trong 
    cùng class. Thí dụ như:</FONT></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>Class</FONT> ClassCha 
   <FONT color=blue>Public</FONT> <FONT color=blue>Sub</FONT> VôĐề() 
      ChàoHỏi() 
   <FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> <BR>
   <FONT color=blue>Public</FONT> <FONT color=blue>Overridable</FONT> <FONT color=blue>Sub</FONT> ChàoHỏi() 
      MessageBox.Show("Chào các cháu", "Class Cha") 
   <FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> 
<FONT color=blue>End</FONT> <FONT color=blue>Class</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial size=2>
    <P>Trong trường hợp nầy, <B>VôĐề</B> gọi <B>Sub ChàoHỏi</B> để đón tiếp. Để 
    ý là vì ChàoHỏi được declared Overridable nên rất có thể một SubClass sẽ 
    implement method ChàoHỏi và lấn quyền nó. Thí dụ:<BR></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>Class</FONT> ClassCon 
   <FONT color=blue>Inherits</FONT> ClassCha 
   <FONT color=blue>Public</FONT> <FONT color=blue>Overrides</FONT> <FONT color=blue>Sub</FONT> ChàoHỏi() 
      MessageBox.Show("Thưa các Bác", "Class Con") 
   <FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> 
<FONT color=blue>End</FONT> <FONT color=blue>Class</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial size=2>
    <P>Vì đặc tính virtual của ChàoHỏi nên ta tưởng ClassCha execute chính Sub 
    ChàoHỏi của nó nhưng té ra nó lại execute code của ChàoHỏi trong ClassCon. 
    Trong code dưới đây, một Object ClassCon gọi Sub VôĐề của 
    ClassCha:<BR></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Private</FONT> <FONT color=blue>Sub</FONT> BtnSubClassObject_Click(<FONT color=blue>ByVal</FONT> sender <FONT color=blue>As</FONT> System.Object,  _
                               <FONT color=blue>ByVal</FONT> e <FONT color=blue>As</FONT> System.EventArgs) <FONT color=blue>Handles</FONT> BtnSubClassObject.Click 
   <FONT color=blue>Dim</FONT> obj <FONT color=blue>As</FONT> <FONT color=blue>New</FONT> ClassCon() 
   obj.VôĐề() 
<FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial size=2>
    <P>Trong ClassCha, Sub VôĐề gọi ChàoHỏi của chính nó, tuy nhiên Sub ChàoHỏi 
    ấy bị overridden bởi implementation của ChàoHỏi trong ClassCon. Do đó, 
    program sẽ hiển thị message "<B>Thưa các Bác</B>".<BR><BR>Nếu ta không muốn 
    như vậy, ta muốn VôĐề execute chính code của ChàoHỏi trong ClassCha thì phải 
    dùng keyword <B>MyClass</B> như sau:<BR></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>Class</FONT> ClassCha 
   <FONT color=blue>Public</FONT> <FONT color=blue>Sub</FONT> VôĐề() 
      <FONT color=blue>MyClass</FONT>.ChàoHỏi() 
   <FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> <BR>
   <FONT color=blue>Public</FONT> <FONT color=blue>Overridable</FONT> <FONT color=blue>Sub</FONT> ChàoHỏi() 
      MessageBox.Show("Chào các cháu", "Class Cha") 
   <FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> 
<FONT color=blue>End</FONT> <FONT color=blue>Class</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial>
    <P><FONT size=2>Ở đây ta không thể dùng keyword <B>Me</B> vì VôĐề có gọi 
    ChàoHỏi ở class-level trong ClassCha chớ không phải trong một SubClass, 
    nhưng bị overridden. Hình dưới đây minh họa quá trình gọi VôĐề từ client 
    code:</FONT></P>
    <BLOCKQUOTE>
      <P><FONT size=2><IMG height=318 src="" width=550></FONT></P></BLOCKQUOTE>
    <P><FONT size=2>Sub VôĐề thật ra nằm trong ClassCha mà ClassCon thừa kế nên 
    VôĐề được executed trong ClassCha và gọi Sub ChàoHỏi trong cùng class ( 
    ClassCha). Nhưng vì ClassCon có một implementation của Sub ChàoHỏi nên nó 
    overrides ChàoHỏi của ClassCha. </FONT></P>
    <H3><FONT color=blue size=2>Overridding Method New</FONT></H3>
    <P><FONT size=2>Chúng ta đã thấy ta có thể override methods và dùng các 
    keywords Me, MyBase và MyClass để gọi các overriden methods trong dây chuyền 
    thừa kế. Tuy nhiên, đối với Constructor của class thì có những luật lệ đặc 
    biệt dành riêng cho method <B>New</B>.<BR><BR>Những methods New không tự 
    động di truyền từ BaseClass xuống SubClass. Mỗi SubClass phải có một 
    implementation riêng cho Constructor dù rằng, nếu muốn, nó có thể gọi vào 
    BaseClass với keyword MyBase:</FONT></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>Class</FONT> ClassCon 
   <FONT color=blue>Inherits</FONT> ClassCha 
   <FONT color=blue>Public Sub</FONT> New()
      <FONT color=blue>MyBase</FONT>.New() 
     <FONT color=green>' để thêm các code khác để initialise tại đây</FONT>
   <FONT color=blue>End</FONT> <FONT color=blue>Sub</FONT> 
<FONT color=blue>End</FONT> <FONT color=blue>Class</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial>
    <P><FONT size=2>Khi gọi Constructor của BaseClass, ta phải gọi nó trước nhất 
    - nếu không sẽ bị error. Tuy nhiên ta không cần gọi Constructor của 
    BaseClass vì Constructor của BaseClass được gọi tự động.<BR><BR>Có một luật 
    đặc biệt là nếu tất cả methods New trong BaseClass đều đòi hỏi parameters 
    thì ta phải implement ít nhất một method New trong SubClass và ta phải đặt 
    statement <B>MyBase.New</B> ngay phía đầu.<BR><BR>Dĩ nhiên là ta có thể 
    Overload method New trong SubClass, nhưng ta phải tự lo liệu cách gọi một 
    method New thích hợp trong BaseClass. </FONT></P>
    <H3><FONT color=blue size=2>Tạo BaseClasses và Abstract Methods</FONT></H3>
    <P><FONT size=2>Cho đến giờ ta đã bàn về virtual method với đặc tính 
    override trong nguyên tắc thừa kế. Trong các thí dụ trước đây BaseClass được 
    instantiated thành Object để làm chuyện nầy, chuyện kia. Nhưng đôi khi ta 
    muốn tạo một BaseClass <I>chỉ để dùng</I> cho thừa kế mà thôi. </FONT></P>
    <H3><FONT color=#800000 size=2>Keyword MustInherit (Phải được Thừa Kế) 
    </FONT></H3>
    <P><FONT size=2>Trở lại cái thí dụ về Inheritance với Class LineItem. Sở dĩ 
    ta đặt ra Class LineItem là vì nó chứa những thứ chung cho cả hai classes 
    ProductLine và ServiceLine. Chớ thật ra một Object của Class LineItem không 
    chứa đủ mọi đặc tính để làm một việc gì thực tế. Nếu ta muốn nói rõ rằng 
    Class LineItem chỉ được dùng để tạo những SubClasses bằng cách thừa kế từ 
    nó, ta có thể declare như sau:</FONT></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>MustInherit</FONT> <FONT color=blue>Class</FONT> LineItem 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial size=2>
    <P>Tức là ta chỉ thêm keyword <B>MustInherit</B> thôi, chớ không thay đổi gì 
    khác. Kết quả là từ nay Client code không thể instantiate một Object từ 
    Class LineItem. Do đó dòng code sau sẽ bị syntax error:<BR></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Dim</FONT> myObject <FONT color=blue>As New</FONT> LineItem() 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial>
    <P><FONT size=2>Thay vào đó, nếu muốn dùng LineItem ta phải tạo SubClass từ 
    nó. </FONT></P>
    <H3><FONT color=#800000 size=2>Keyword MustOverride (Phải bị Lấn 
    Quyền)</FONT></H3>
    <P><FONT size=2>Tương tự với ý niệm Phải-được-thừa-kế trong Class, ta cũng 
    có <B>MustOverride</B> cho một method. Có thể trong BaseClass ta khai báo 
    một method, nhưng ta đòi hỏi method ấy phải có một implementation trong 
    SubClass. Ta declare như sau:</FONT></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Dim</FONT> <FONT color=blue>MustOverride Sub</FONT> CalculatePrice 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial>
    <P><FONT size=2>Để ý là ở đây không có thân thể của Sub CalculatePrice hay 
    statement End Sub gì cả. Khi dùng MustOverride ta không được phép cung cấp 
    một implementation cho method trong BaseClass. Một method như thế được gọi 
    là <B>abstract method</B> hay <B>pure virtual function</B>, vì nó chỉ có 
    phần khai báo chớ không có phần định nghĩa. Những abstract methods phải được 
    overridden trong bất cứ SubClass nào của BaseClass thì mới dùng được. Nếu 
    không, ta sẽ không có phần implementation của method đâu cả và khi compile 
    sẽ gặp syntax error. </FONT></P>
    <H3><FONT color=#800000 size=2>Abstract Base Classes</FONT></H3>
    <P><FONT size=2>Nếu hợp cả hai ý niệm MustInherit và MustOverride lại ta sẽ 
    tạo ra một <B>abstract base class</B>. Đây là một Class chỉ có khai báo chớ 
    hoàn toàn không có implementation. Ta phải SubClass từ nó thì mới làm việc 
    được, thí dụ như:</FONT></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>MustInherit</FONT> <FONT color=blue>Class</FONT> ClassCha 
   <FONT color=blue>Public</FONT> MustOverride <FONT color=blue>Sub</FONT> VôĐề() 
   <FONT color=blue>Public</FONT> MustOverride <FONT color=blue>Sub</FONT> ChàoHỏi() 
<FONT color=blue>End</FONT> <FONT color=blue>Class</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial size=2>
    <P>Kỹ thuật nầy rất thích hợp để ta code cái sườn hay bố cục của program 
    ngay trong lúc thiết kế. Class nào thừa kế <B>ClassCha</B> thì phải 
    implement cả <B>Sub VôĐề</B> lẫn <B>Sub ChàoHỏi</B>, nếu không sẽ bị syntax 
    error.<BR><BR>Nhìn về một phương diện, abstract base class rất giống khai 
    báo Interface. Nếu dùng Interface, chúng ta có thể khai báo như 
    sau:<BR></P></FONT>
    <TABLE bgColor=#f6f6f6>
      <TBODY>
      <TR>
        <TD><FONT size=3><PRE><FONT face=Arial><FONT color=blue>Public</FONT> <FONT color=blue>Interface</FONT> ICha 
   <FONT color=blue>Sub</FONT> VôĐề() 
   <FONT color=blue>Sub</FONT> ChàoHỏi() 
<FONT color=blue>End</FONT> <FONT color=blue>Interface</FONT> 
</FONT></PRE></FONT></TD></TR></TBODY></TABLE><FONT face=Arial size=2>
    <P>Bất cứ class nào chịu implement interface <B>ICha</B> thì phải implement 
    cả <B>Sub VôĐề</B> lẫn <B>Sub ChàoHỏi</B>, nếu không sẽ bị syntax error - do 
    đó, ta thấy Interface rất giống một abstract base class.<BR><BR>Sự khác biệt 
    chính giữa abstract base class với Interface là ở chỗ thừa kế. Khi ta tạo 
    một class con bằng cách SubClass từ ClassCha, chính class con ấy lại cũng có 
    thể được SubClassed. Mấy class cháu nầy sẽ tự động thừa kế VôĐề và ChàoHỏi 
    từ class con.<BR><BR>Trong khi ấy nói về Interface, mỗi class phải tự 
    implement ICha một cách độc lập và phải cung cấp hai Subs VôĐề và ChàoHỏi 
    của chính nó. Vì thế, nếu ta không có ý định dùng lại code của các Subs khi 
    ta tạo các classes mới thì ta có thể dùng interface. Ngược lại nếu ta muốn 
    dùng lại code trong SubClass theo nguyên tắc thừa kế thì ta nên dùng 
    abstract base class. </P></FONT></FONT><!-- Start of bottom bar for copyright notice etc -->
    <TABLE class=clsNavLinks id=tblFooterLinks cellSpacing=0 cellPadding=0 
    width="100%" border=0>
      <TBODY>
      <TR>
        <TD class=clsRaised width=785 bgColor=#6699cc colSpan=5>
          <P align=center><FONT face=Arial color=#ffffff size=2>Vovisoft © 2000. 
          All rights reserved.</FONT></P></TD></TR>
      <TR>
        <TD width=256>
          <P align=center><FONT face=Arial size=2>&nbsp;&nbsp; Last Updated: <!--webbot 
      bot="Timestamp" S-Type="REGENERATED" S-Format="%d %b %Y" startspan -->06 
          th3 2002<!--webbot 
      bot="Timestamp" endspan i-checksum="13300" --> </FONT></P></TD>
        <TD width=181><FONT face=Arial size=2>&nbsp;</FONT></TD>
        <TD width=258>
          <P align=center><FONT face=Arial size=2><A 
          href="mailto:dixon@vovisoft.com">Webmaster</A></FONT></P></TD></TR></TBODY></TABLE></BLOCKQUOTE></BLOCKQUOTE>
<HR>

<P align=center><FONT face="Times New Roman"><B><FONT color=#ff0000>PcLeHoan 
1996 - 2002</FONT><FONT face=.VnTime size=2><BR></FONT></B></FONT><FONT 
face="Times New Roman" size=2><B>Mirror </B>: <A 
href="http://www.pclehoan.com/andi/ndc.htm">http://www.pclehoan.com/andi/ndc.htm</A><BR><B>Mirror 
</B>: <A 
href="http://www.lehoanpc.net/andi/ndc.htm">http://www.lehoanpc.net/andi/ndc.htm</A></FONT><BR><FONT 
face="Times New Roman" size=2><B>Mirror </B>: <A 
href="http://www.ktlehoan.com/">http://www.ktlehoan.com/</A></FONT></P>
<P align=center><A target=_top 
href="http://member.bcentral.com/cgi-bin/fc/fastcounter-login?2828564"><IMG 
src="5_files/digits.gif" border=0></A> </P></BODY></HTML>
